using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace PengYouClient
{
    public class DavRessource
    {
        DAVSharp.DavServerConnection DAVc;

        public DavContext context;
        public string ressource;
        public bool PropFindAll_done = false;

        public ArrayList directory_listing;     
   
        // GetRessource

        public DAVSharp.ProgressContainer sendContainer;
        public DAVSharp.ProgressContainer receiveContainer;

        // 

        // Error codes

        DAVSharp.WebDavStatusCode resultCode;
        string resultReason;
        string resultContent;

        //

        public DAVSharp.WebDavStatusCode ResultCode
        {
            get
            {
                return resultCode;
            }
        }

        public string ResultReason
        {
            get
            {
                return resultReason;
            }
        }

        public string ResultContent
        {
            get
            {
                return resultContent;
            }
        }

        public ulong downloadedBytes
        {
            get
            {
                return receiveContainer.TotalBytes;
            }
        }

        public ulong fileSize
        {
            get
            {
                return receiveContainer.TotalBytesExpected;
            }
        }
        /// <summary>
        /// Create the ressource object
        /// </summary>
        /// <param name="ressource">Relative ressource URI on the server (ie: test.doc)</param>
        /// <param name="context">Context object (ressource absolute URI, server address, pass, port)</param>
        public  DavRessource(string ressource, DavContext context) {
            this.ressource = ressource;
            this.context = context;
            DAVc = new DAVSharp.DavServerConnection(context.server_uri);
            if (context.password != null)
                DAVc.Password = context.password;
            if (context.username != null)
                DAVc.Username = context.username;
        }

        /// <summary>
        /// Make a propfindall for the ressource
        /// </summary>
        /// <param name="return_dirlist">Array containing the content of the directory)</param>
        /// <returns></returns>
        public bool GetDirectoryListing(out ArrayList return_dirlist)
        {
            bool success;

            this.directory_listing = new ArrayList();
            success = DavPropFindAll(1);
            return_dirlist = this.directory_listing;
            return success;
        }

        /// <summary>
        /// Get the ressource as a filestream
        /// </summary>
        /// <param name="Content">Ressource Filestream</param>
        /// <returns></returns>
        public bool GetRessource(out FileStream Content)
        {
            sendContainer = new DAVSharp.ProgressContainer();
            receiveContainer = new DAVSharp.ProgressContainer();
            bool success = DAVc.GetResource(this.ressource,
                out resultCode, out resultReason, out resultContent, out Content, sendContainer, receiveContainer);
            Content.Close();
            return success;
        }

        /// <summary>
        /// Propfind all method interface for the library
        /// </summary>
        /// <param name="depth">See Webdav RFC</param>
        /// <returns></returns>
        public bool DavPropFindAll(int depth) {
            Hashtable prop = new Hashtable();
            string res = this.ressource;
            bool success;

            success = DAVc.PropfindAll(res, out this.resultCode, out this.resultReason, out prop);
            if (success == false)
                return success;
            
            IDictionaryEnumerator dicenum = prop.GetEnumerator();
            while (dicenum.MoveNext())
            {
                Hashtable element = new Hashtable();

                string relativename;
                string versionname;
                string last_modified;
                string creation_date;
                string owner;
                string comment;
                bool is_dir = false;
                DateTime lm;
                DateTime cd;
                string ress_withoutbackslash = "";

                element.Add("ressource_name", dicenum.Key);
//                versionname = ((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:version-name"].ToString();
                try
                {
                    if (((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:resourcetype"] != null)
                    {
                        is_dir = true;
                    }
                }
                catch (Exception)
                {
                }
                try
                {
                    versionname = ((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:version-name"].ToString();
                }
                catch (Exception)
                {
                    versionname = null;
                }
                try
                {
                    last_modified = ((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:getlastmodified"].ToString();
                    DateTime.TryParse(last_modified, out lm);
                }
                catch (Exception)
                {
                    lm = DateTime.Now;
                }
                try
                {
                    creation_date = ((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:creationdate"].ToString();
                    DateTime.TryParse(creation_date, out cd);
                }
                catch (Exception)
                {
                    cd = DateTime.Now;
                }
                if (is_dir == true)
                {                    
                    if (dicenum.Key.ToString().EndsWith("/"))
                        ress_withoutbackslash = dicenum.Key.ToString().Remove(dicenum.Key.ToString().LastIndexOf("/"));
                    else
                        ress_withoutbackslash = dicenum.Key.ToString();
                    relativename = ress_withoutbackslash.Remove(0, ress_withoutbackslash.LastIndexOf("/") + 1);
                }
                else
                    relativename = dicenum.Key.ToString().Remove(0, dicenum.Key.ToString().LastIndexOf("/") + 1);
                try
                {
                    owner = ((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:creator-displayname"].ToString();
                }
                catch (Exception)
                {
                    owner = "";
                }
                try
                {
                    comment = ((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:description"].ToString();
                }
                catch (Exception)
                {
                    comment = "";
                }
                element.Add("name", relativename);
                element.Add("last_author", owner);
                element.Add("last_modified", lm);
                element.Add("is_dir", is_dir);
                element.Add("creation_date", cd);
                element.Add("version", versionname);
                element.Add("comment", comment);
                try
                {
                    if (res.CompareTo(ress_withoutbackslash) != 0)
                        directory_listing.Add(element);
                }
                catch (Exception e)
                {
                    System.Console.WriteLine(e.Message);
                }
            }
            return success;
        }

        /// <summary>
        /// Send a ressource on the server
        /// </summary>
        /// <param name="uploadbyte">byte table representing the ressource content</param>
        /// <returns></returns>
        public bool SendRessource(byte[] uploadbyte)
        {
            sendContainer = new DAVSharp.ProgressContainer();
            receiveContainer = new DAVSharp.ProgressContainer();
            Uri ress = new Uri(this.ressource);
            bool success = DAVc.PutResource(ress.AbsoluteUri, "application/msword", uploadbyte, 
                out resultCode, out resultReason, out resultContent, sendContainer, receiveContainer);            
            return success;
        }

        /// <summary>
        /// Check out the ressource
        /// </summary>
        /// <returns></returns>
        public bool CheckOut()
        {
            sendContainer = new DAVSharp.ProgressContainer();
            receiveContainer = new DAVSharp.ProgressContainer();
            Uri ress = new Uri(this.ressource);
            bool success = DAVc.CheckOut(ress.AbsoluteUri, out resultCode, out resultReason, 
                out resultContent, sendContainer, receiveContainer);
            return success;
        }

        /// <summary>
        /// Check in the ressource
        /// </summary>
        /// <returns></returns>
        public bool CheckIn()
        {
            sendContainer = new DAVSharp.ProgressContainer();
            receiveContainer = new DAVSharp.ProgressContainer();
            Uri ress = new Uri(this.ressource);
            bool success = DAVc.CheckIn(ress.AbsoluteUri, out resultCode, out resultReason,
                out resultContent, sendContainer, receiveContainer);
            return success;
        }

        /// <summary>
        /// Set a property (propatch) for the ressource.
        /// </summary>
        /// <param name="property">Property to set</param>
        /// <param name="value">Value of the property</param>
        /// <returns></returns>
        public bool SetProperty(string property, string value)
        {
            sendContainer = new DAVSharp.ProgressContainer();
            receiveContainer = new DAVSharp.ProgressContainer();
            Hashtable prop = new Hashtable();
            bool success = DAVc.PropPatch(ressource, out resultCode, out resultReason,
                out resultContent, sendContainer, receiveContainer, property, value, out prop);
            try
            {
                string result = ((string)((Hashtable)((Hashtable)prop[ressource])[DAVSharp.WebDavStatusCode.OK])["DAV Sharp Reason String Key"]);
                success = true;
            }
            catch (Exception)
            {
                success = false;
            }
            if (!success)
                return false;
            return true;
        }

        /// <summary>
        /// Put the ressource under revision
        /// </summary>
        /// <returns></returns>
        public bool PutUnderRevision()
        {
            sendContainer = new DAVSharp.ProgressContainer();
            receiveContainer = new DAVSharp.ProgressContainer();
            Uri ress = new Uri(this.ressource);
            bool success = DAVc.PutUnderRevision(ress.AbsoluteUri, out resultCode, out resultReason,
                out resultContent, sendContainer, receiveContainer);
            return success;
        }

        /// <summary>
        /// Head on the ressource
        /// </summary>
        /// <returns></returns>
        public bool FileExists()
        {
            sendContainer = new DAVSharp.ProgressContainer();
            receiveContainer = new DAVSharp.ProgressContainer();
            Uri ress = new Uri(this.ressource);
            bool success = DAVc.Head(ress.AbsoluteUri, out resultCode, out resultReason,
                out resultContent, sendContainer, receiveContainer);
            return success;
        }

        /// <summary>
        /// Report on the ressource
        /// </summary>
        /// <param name="versions">Array containing the version name, number like in the Directory listing</param>
        /// <returns></returns>
        public bool Report(out ArrayList versions)
        {             
            sendContainer = new DAVSharp.ProgressContainer();
            receiveContainer = new DAVSharp.ProgressContainer();
            Hashtable prop = new Hashtable();
            bool success = DAVc.Report(ressource, out resultCode, out resultReason,
                out resultContent, sendContainer, receiveContainer, out prop);
            if (!success)
            {
                versions = null;
                return false;
            }
            IDictionaryEnumerator dicenum = prop.GetEnumerator();
            ArrayList localversion = new ArrayList();
            while (dicenum.MoveNext())
            {
                Hashtable element = new Hashtable();
                string vname;
                string vlastmodified;
                string comment;
                string owner;
                try
                {
                    vname = ((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:version-name"].ToString();
                }
                catch (Exception)
                {
                    vname = "";
                    success = false;
                }
                try
                {
                    vlastmodified = ((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:getlastmodified"].ToString();
                }
                catch (Exception)
                {
                    vlastmodified = "";
                    // eXo does not support this prop
                    // success = false;
                }
                try
                {
                    comment = ((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:comment"].ToString();
                }
                catch (Exception)
                {
                    comment = "";
                }
                try
                {
                    owner = ((Hashtable)((Hashtable)(dicenum.Value))[DAVSharp.WebDavStatusCode.OK])["DAV:creator-displayname"].ToString();
                }
                catch (Exception)
                {
                    owner = "";
                }
                element.Add("version-name", vname);
                element.Add("version-lastmodified", vlastmodified);
                element.Add("version-comment", comment);
                element.Add("version-owner", owner);
                element.Add("version-href", dicenum.Key.ToString());
                if (vname != "jcr:rootVersion")
                    localversion.Add(element);
            }
            versions = localversion;
            return success;
        }
     }
}
